﻿using CaseManagerLibrary.Http;
using CaseManagerLibrary.Models;
using Newtonsoft.Json;
using PSDClientService.SystemSettings;
using PSDLib;
using PSDLib.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace PSDClientService.Burn
{
    public delegate void BurnJobDeniedEventHandler(BurnJob job, int dvdNum, int resultCode);
    public class BurnManager
    {
        private BurnContext context;

        public event BurnJobDeniedEventHandler OnBurnJobDenied;
        /// <summary>
        /// 所有刻录任务列表
        /// </summary>
        public BurnTaskList BurnTasks { get; set; }
        /// <summary>
        /// 同步刻录任务列表
        /// </summary>
        public List<BurnTask> SyncBurnList { get; set; }

        public List<BurnJob> BurnJobList { get; set; }
        /// <summary>
        /// 正在处理的刻录作业
        /// </summary>
        private int ProcessingBurnJobCount { get; set; }
        private object lock_burnJobCount = new object();
        //public Dictionary<string, BurnJobQueue> BurnJobDataSet;
        private bool burnJobCreateSuspend = false;
        private object lock_burnJobCreateSuspend = new object();
        /// <summary>
        /// 是否挂起后续刻录作业的处理
        /// </summary>
        public bool IsSuspend
        {
            get
            {
                bool result;

                lock (lock_burnJobCreateSuspend)
                {
                    result = burnJobCreateSuspend;
                }

                return result;
            }
        }

        private System.Timers.Timer immeJobTimer;

        public BurnManager(BurnContext ctx)
        {
            context = ctx;

            BurnTasks = new BurnTaskList();
            SyncBurnList = new List<BurnTask>();
            BurnJobList = new List<BurnJob>();

            ProcessingBurnJobCount = 0;

            immeJobTimer = new System.Timers.Timer();
            immeJobTimer.Interval = 50000;
            immeJobTimer.Elapsed += ImmeJobTimer_Elapsed;
        }

        private void ImmeJobTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            //如果刻录作业处理被挂起，则不再处理新的刻录作业
            if (IsSuspend)
                return;

            lock (lock_burnJobCount)
            {
                //如果当前处理的刻录作业数量大于等于刻录光驱数量，则不再处理新的刻录作业
                if (ProcessingBurnJobCount >= context.ClientContext.DeviceManager.RecorderList.Count)
                    return;
            }

            //处理新的刻录作业
            ProcessImmediateBurnJob();
        }

        public void Start()
        {
            immeJobTimer.Start();
        }

        public void Stop()
        {
            immeJobTimer.Stop();
        }

        //public void CreateBurnJobQueue(RecorderDevice recorder)
        //{
        //    BurnJobQueue queue = new BurnJobQueue(context, recorder);

        //    BurnJobDataSet.Add(recorder.RecorderId, queue);
        //}

        ///// <summary>
        ///// 添加一个刻录任务
        ///// </summary>
        ///// <param name="task"></param>
        //public void AddTask(BurnTask task)
        //{
        //    BurnTasks.Add(task);

        //    if (task.BurnInfo.burn_mode == (int)BurnMode.ImmediateBurn)
        //    {
        //        ImmediateBurn(task);
        //    }
        //    else if (task.BurnInfo.burn_mode == (int)BurnMode.SyncBurn)
        //    {
        //        SyncBurn(task);
        //    }
        //}

        /// <summary>
        /// 获取一个可用刻录光驱，并开始刻录
        /// </summary>
        /// <param name="dvd"></param>
        /// <returns></returns>
        public int BeginBurnJob(RecorderDevice device, BurnJob burnJob)
        {
            int result = (int)ResultCode.Failed;

            if (device != null)
            {
                try
                {
                    //更新刻录运行时状态
                    var status = context.BurnRuntime.GetRecorderStatus(device.RecorderId);
                    status.State = (int)ResultCode.RecorderWorking;

                    //开始刻录

                    device.SeBurnJob(burnJob);
                    result = device.StartBurn(burnJob.DVD.dvd_title, false, true);
                }
                catch (Exception ex)
                {
                    context.Logger.Error("开始刻录失败：" + ex.Message + (ex.InnerException == null ? "" : ex.InnerException.Message));
                }
            }

            return result;
        }

        /// <summary>
        /// 结束刻录，将光盘从正在刻录光盘列表中移除
        /// </summary>
        /// <param name="dvdId"></param>
        public void EndBurnJob(RecorderDevice device, BurnJob burnJob)
        {
            if (burnJob != null)
            {
                //更新光盘刻录状态
                var ret_dvd = HttpHelper.Post<HResult>(AppSettings.Setting.API.BurnDVDComplete, JsonConvert.SerializeObject(burnJob.DVD));

                if (ret_dvd.success)
                {
                    //更新任务状态
                    var task = BurnTasks.Where(t => t.BurnInfo.id == burnJob.BurnInfo.id).FirstOrDefault();

                    if (task != null)
                    {
                        bool finish = true;
                        foreach (var d in task.DVDList)
                        {
                            if (d.state < (int)BurnDVDState.刻录完成)
                            {
                                finish = false;
                                break;
                            }
                        }

                        if (finish)
                        {
                            task.BurnInfo.state = (int)BurnDVDState.刻录完成;

                            var ret = HttpHelper.Post<HResult>(AppSettings.Setting.API.BurnComplete, JsonConvert.SerializeObject(task.BurnInfo));

                            if (ret.success)
                            {
                                BurnTasks.Remove(task);
                            }
                        }
                    }
                }

                //释放刻录光驱
                context.ClientContext.DeviceManager.ReleaseDevice(device.RecorderId);

                //更新刻录运行时状态
                var status = context.BurnRuntime.GetRecorderStatus(device.RecorderId);
                status.State = (int)ResultCode.RecorderFree;
                context.BurnRuntime.BurnJobs.Remove(burnJob);

                //更新刻录任务计数
                ProcessingBurnJobDecrease();
            }
        }

        /// <summary>
        /// 立即刻录，要刻录的文件一次性提交
        /// </summary>
        /// <param name="task"></param>
        public void ImmediateBurn(BurnTask task)
        {
            BurnTasks.Add(task);

            //为每张光盘创建对应的刻录作业
            List<BurnJob> jobList = new List<BurnJob>();
            foreach (var dvd in task.DVDList)
            {
                BurnJob job = new BurnJob();
                job.Id = dvd.id;
                job.BurnInfo = task.BurnInfo;
                job.DVD = dvd;
                job.Files.AddRange(task.FileList.Where(t => t.dvd_id == dvd.id).ToList());
                jobList.Add(job);
            }

            //根据刻录份数复制刻录作业
            List<BurnJob> copyList = new List<BurnJob>();
            for (int i = 1; i < task.BurnInfo.burn_copy; i++)
            {
                foreach (var job in jobList)
                {
                    copyList.Add(job.Clone());
                }
            }

            //添加到刻录作业队列
            lock (lock_burnJobCount)
            {
                BurnJobList.AddRange(jobList);
                BurnJobList.AddRange(copyList);
            }

            //foreach (var job in jobList)
            //{
            //    RecorderDevice device = null;
            //    int result = context.ClientContext.DeviceManager.GetFreeDevice(out device);

            //    if (result == (int)ResultCode.Success)
            //    {
            //        BeginBurnDVD(device, job);
            //    }
            //    else
            //    {
            //        OnBurnTaskDenied?.Invoke(task, job.DVD.dvd_num, result);
            //    }
            //}
        }

        /// <summary>
        /// 增加正在处理的刻录作业计数
        /// </summary>
        public void ProcessingBurnJobIncrease()
        {
            lock (lock_burnJobCount)
            {
                ProcessingBurnJobCount += 1;
            }
        }

        /// <summary>
        /// 减少正在处理的刻录作业计数
        /// </summary>
        public void ProcessingBurnJobDecrease()
        {
            lock (lock_burnJobCount)
            {
                ProcessingBurnJobCount -= 1;
            }
        }

        /// <summary>
        /// 挂起对新的刻录作业的处理
        /// </summary>
        public void Suspend()
        {
            lock (lock_burnJobCreateSuspend)
            {
                burnJobCreateSuspend = true;
            }
        }

        /// <summary>
        /// 恢复对新的刻录作业的处理
        /// </summary>
        public void Resume()
        {
            lock (lock_burnJobCreateSuspend)
            {
                burnJobCreateSuspend = false;
            }
        }

        /// <summary>
        /// 处理一个刻录作业
        /// </summary>
        private void ProcessImmediateBurnJob()
        {
            //挂起操作，暂停处理新的刻录作业
            Suspend();

            bool burnJobCreated = false;
            int result = (int)ResultCode.Failed;

            BurnJob job = BurnJobList.FirstOrDefault();

            if (job == null)
            {
                Resume();
                return;
            }

            //增加当前处理刻录作业计数
            ProcessingBurnJobIncrease();

            if (job.State == (int)ResultCode.BurnJobWaiting)
            {
                //添加到刻录运行时
                context.BurnRuntime.BurnJobs.Add(job);

                //获取可用光驱
                RecorderDevice device;
                result = context.ClientContext.DeviceManager.GetFreeDevice(out device);

                if (result == (int)ResultCode.Success)
                {
                    burnJobCreated = (BeginBurnJob(device, job) == (int)ResultCode.Success);
                }
                else
                {
                    OnBurnJobDenied?.Invoke(job, job.DVD.dvd_num, result);
                }
            }
            else if (job.State == (int)ResultCode.BurnJobSuspend)
            { }

            //如果刻录作业未创建，减少当前处理刻录作业计数
            if (!burnJobCreated)
            {
                ProcessingBurnJobDecrease();
            }

            //取消挂起，恢复处理下一个刻录作业
            if (result == (int)ResultCode.Success)
            {
                Resume();
            }
        }

        #region 同步刻录相关
        ///// <summary>
        ///// 同步刻录，与文件下载同步，满一张光盘容量后刻录一张
        ///// </summary>
        ///// <param name="task"></param>
        //private void SyncBurn(BurnTask task)
        //{
        //    task.OnDVDReadyToBurn += Task_OnDVDReadyToBurn;
        //    SyncBurnList.Add(task);
        //}

        ///// <summary>
        ///// 光盘准备刻录事件
        ///// </summary>
        ///// <param name="dvd"></param>
        //private void Task_OnDVDReadyToBurn(dl_burn_dvd dvd)
        //{
        //    //BeginBurnDVD(burnJob);
        //}


        ///// <summary>
        ///// 添加刻录文件
        ///// </summary>
        ///// <param name="burnId"></param>
        ///// <param name="file"></param>
        //public void AddBurnFile(string burnId, dl_files file)
        //{
        //    var task = BurnTasks.Where(t => t.BurnInfo.id == burnId).FirstOrDefault();

        //    if (task != null)
        //    {
        //        dl_burn_files bf = new dl_burn_files();
        //        bf.id = Guid.NewGuid().ToString();
        //        bf.burn_id = burnId;
        //        bf.dl_task_id = task.BurnInfo.dl_task_id;
        //        bf.file_id = file.id;
        //        bf.file_name = file.file_name;
        //        bf.file_path = file.file_path;
        //        bf.file_size = file.file_size;
        //        bf.dvd_file_name = file.file_name;
        //        bf.dvd_file_path = "";
        //        bf.state = 0;

        //        task.AddFile(bf);
        //    }
        //}

        #endregion
    }
}
